home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 20 / Cream of the Crop 20 (Terry Blount) (1996).iso / utility / freedos.zip / COM050.ZIP / LOADHIGH.C < prev    next >
C/C++ Source or Header  |  1996-01-17  |  15KB  |  516 lines

  1. /*
  2.     LOADHIGH.C - command that loads a DOS executable into upper memory.
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. */
  19.  
  20. /*
  21.  * LOADHIGH.C
  22.  *
  23.  *
  24.  *   Comments
  25.  *
  26.  * ??/??/96 (Svante Frey) -------------------------------------------------
  27.  *   began.
  28.  *
  29.  * 01/17/96 (Tim Norman) --------------------------------------------------
  30.  *   plugged into COMMAND.COM
  31.  *
  32.  */
  33.  
  34. #include <string.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <ctype.h>
  38. #include <fcntl.h>
  39. #include <dos.h>         /* must have those MK_FP() macros */
  40. #include "command.h"     /* command shell interface functions */
  41. #include "loadhigh.h"    /* contains macros, global variables, etc */
  42.  
  43. /* This module takes care of both the LOADHIGH and the LOADFIX command,
  44.  * since those two commands have much in common.
  45.  *
  46.  * The global variable 'loadfix_flag' is used to keep track of which 
  47.  * command is currently executing. If this variable is non-zero, it's 
  48.  * LOADFIX, otherwise LOADHIGH.
  49.  */
  50.  
  51. /* This is the loadhigh handler */
  52. #pragma argsused
  53. void loadhigh(int argc, char *argv[128], char *args)
  54. {
  55.    loadfix_flag = 0;
  56.    lh_lf(args);
  57. }
  58.  
  59. /* This is the loadfix handler */
  60. #pragma argsused
  61. void loadfix(int argc, char *argv[128], char *args)
  62. {
  63.    loadfix_flag = 1;
  64.    lh_lf(args);
  65. }
  66.  
  67. /* This is the "real" handler of the two commands. The argument is
  68.  * the original command line.
  69.  */
  70.  
  71. int lh_lf(char *args)
  72. {
  73.    int  rc = err_out_of_memory;
  74.    char *fullname = malloc(128);
  75.    char **paths = malloc(128 * sizeof(*paths));
  76.    filename = malloc(128);
  77.  
  78.    if (paths && fullname && filename)
  79.    {    
  80.        if (initialise() == OK) 
  81.        {          
  82.           if ((rc = parseArgs(args)) == OK)
  83.           {
  84.              /* command line was OK - try to find the file */
  85.              get_paths(paths);
  86.  
  87.              if (find_which(paths, filename, fullname) == 1)
  88.              {
  89.                 /* a file was found - allocate the memory */
  90.                 if (loadfix_flag)
  91.                     rc = loadfix_prepare();
  92.                 else rc = loadhigh_prepare();
  93.  
  94.                 /* finally, execute the file */
  95.                 if (!rc) rc = exec(fullname, newcmdline, 0);
  96.              }
  97.              else rc = err_file_not_found;
  98.           }
  99.        }
  100.        cleanup();
  101.        free(paths);
  102.        free(fullname);
  103.        free(filename);
  104.    }
  105.  
  106.    /* if any error occurred, rc will hold the error code */
  107.    if (rc) lh_error(rc);
  108.  
  109.    return rc;
  110. }
  111.  
  112. int initialise(void)
  113. {
  114.    int rc;
  115.  
  116.    /* reset global variables */
  117.    swShrink = swLoad = 0;
  118.    allocatedBlocks = 0;        
  119.    upper_flag = 1;
  120.  
  121.    /* Save the UMB link state and the DOS malloc strategy, to restore them later */
  122.    old_link = DosSetUMBLink(1);
  123.    old_strat = DosSetStrategy(0);
  124.  
  125.    /* Allocate dynamic memory for some arrays */
  126.    if (!(umbRegion = malloc(64 * sizeof(*umbRegion))))
  127.        return err_out_of_memory;
  128.  
  129.    if (!(block = malloc(256 * sizeof(*block))))
  130.        return err_out_of_memory;
  131.  
  132.    /* find the UMB regions */
  133.    if ((rc = findUMBRegions()) != 0)
  134.        return rc;
  135.  
  136.    return OK;
  137. }
  138.  
  139. void cleanup(void)
  140. {
  141.    int i;
  142.  
  143.    /* free any memory that was allocated to prevent the program from using it */
  144.    for (i = 0; i < allocatedBlocks; i++)
  145.         DosFree(block[i]);
  146.  
  147.    /* free dynamic arrays */
  148.    free(umbRegion);
  149.    free(block);
  150.  
  151.    /* Restore UMB link state and DOS malloc strategy to their 
  152.       original values. */
  153.  
  154.    DosSetUMBLink(old_link);
  155.    DosSetStrategy(old_strat); 
  156. }
  157.  
  158. /* lh_error(): print error messages to stderr */
  159.  
  160. void lh_error(int errcode)
  161. {
  162.    if (errcode > err_help)
  163.        fprintf (stderr, "ERROR: ");
  164.  
  165.    switch(errcode)
  166.    {
  167.       case err_invalid_parms:
  168.         fprintf (stderr, "%s\n", BADUSAGE);
  169.         /* fall-through to show usage */
  170.       case err_help:
  171.         fprintf (stderr, "%s\n\n", loadfix_flag? loadfix_usage : loadhigh_usage);
  172.         break;
  173.       case err_file_not_found:
  174.         fprintf (stderr, "%s\n", FILENOTFOUND);
  175.         break;
  176.       case err_out_of_memory:
  177.         fprintf (stderr, "%s\n", OUTOFMEMORY);
  178.         break;
  179.       case err_mcb_chain: /* error while searching the MCB chain */
  180.         fprintf (stderr, "%s\n", BADMCBCHAIN);
  181.         break;
  182.       default:
  183.         fprintf (stderr, "error code %d\n", errcode);
  184.    }
  185. }
  186.  
  187. /* findUMBRegions():
  188.  *
  189.  * This routine scans the MCB chain to find all active memory regions.
  190.  * Info about the regions is written to the array "umbRegions".
  191.  *
  192.  * Each continous region is numbered. Region 0 is the conventional 
  193.  * memory.
  194.  */
  195.  
  196. int findUMBRegions(void)
  197. {
  198.   struct UMBREGION *region = umbRegion;
  199.   struct MCB far *mcb = MK_FP(GetFirstMCB(), 0);  /* get start of MCB chain */
  200.   char sig;
  201.   int i;
  202.  
  203.   umbRegions = 0;
  204.   region->start = FP_SEG(mcb);
  205.  
  206.   /* First, find the end of the conventional memory:
  207.      Turn UMB link off, and track the MCB chain to the end. */
  208.  
  209.   DosSetUMBLink(0);
  210.  
  211.   while (mcb->sig == 'M') FP_SEG(mcb) += mcb->size + 1;
  212.       
  213.   if (mcb->sig != 'Z') return err_mcb_chain;
  214.  
  215.   /* If the last memory block in conventional memory is "reserved",
  216.      conventional memory ends at the paragraph before the block. If 
  217.      the last block is an ordinary one, conventional memory ends at 
  218.      the last paragraph of the block. */
  219.  
  220.   if (mcb->owner == 8 && !farmemcmp(mcb->name, "SC", 2))
  221.       region->end = FP_SEG(mcb) - 1;
  222.   else region->end = FP_SEG(mcb) + mcb->size;
  223.      
  224.   region++;
  225.   region->start = 0;
  226.  
  227.   /* Turn UMB link on. If MS-DOS UMBs are available, the signature of
  228.      the last conventional memory block will change from 'Z' to 'M'. */
  229.  
  230.   DosSetUMBLink(1);
  231.  
  232.   if (mcb->sig == 'M') {            /* UMBs are available */
  233.       FP_SEG(mcb) += mcb->size + 1;   /* go to next block */
  234.  
  235.       /* This loop searches for the regions, by searching either for
  236.          special MCBs or 'reserved' memory regions. */
  237.  
  238.       do {
  239.          sig = mcb->sig;
  240.           
  241.          if (mcb->owner == 8 && !farmemcmp(mcb->name, "SC", 2)) {
  242.              /* this is a 'hole' in memory */
  243.              if (region->start) {
  244.                  region->end = FP_SEG(mcb) - 1;
  245.                  region++;
  246.                  region->start = 0;
  247.              }
  248.          } else { 
  249.              /* In MS-DOS 6.x, each UMB region starts with a 'major' mcb 
  250.                 that is outside the ordinary MCB chain. This mcb defines 
  251.                 the size of the whole region. */
  252.  
  253.              struct MCB far *umb_mcb = mcb;
  254.              FP_SEG(umb_mcb)--;
  255.     
  256.              if (umb_mcb->sig == 'Z' || umb_mcb->sig == 'M') 
  257.                  if (!farmemcmp(umb_mcb->name, "UMB     ", 8)) {
  258.                      /* This is the signature of the special MS-DOS MCBs */
  259.                      
  260.                      mcb = umb_mcb;
  261.                      region->start = mcb->owner;
  262.                      region->end = mcb->owner + mcb->size - 1;
  263.                      if ((sig = mcb->sig) == 'M') region->end--;
  264.                      region++;
  265.                      region->start = 0;
  266.                      FP_SEG(mcb) += mcb->size;
  267.                      if (sig == 'Z') break;
  268.                      continue;
  269.                   }
  270.              if (!region->start) 
  271.                  region->start = FP_SEG(mcb);
  272.          } 
  273.  
  274.          if (sig == 'Z') {
  275.              region->end = FP_SEG(mcb) + mcb->size;
  276.              region++;
  277.          }
  278.